Skip to content

aoでのトークンの構築

トークンを作成する際には、ao内でLua言語を引き続き使用してトークンをミントします。これは、トークンスペシフィケーションで概説された原則に従います。

トークンを作成する2つの方法:

1 - トークンブループリントを使用する:

.load-blueprint token

トークンブループリントを使用すると、すでにすべてのハンドラと状態が定義されたトークンが作成されます。これはトークンを作成する最も簡単な方法です。ブループリントを読み込んだ後、これらのハンドラと状態をカスタマイズすることができます。

利用可能なブループリントについてさらに学ぶには、こちらを参照してください: ブループリント

INFO

トークンブループリントを使用すると迅速にトークンが作成できますが、ニーズに合わせてカスタマイズできるように、トークンの読み込みとテスト方法も理解しておく必要があります。

2 - ゼロから構築する:

以下のガイドでは、ゼロからトークンを作成するプロセスを案内します。これはトークンを作成するより高度な方法ですが、トークンの仕組みをより深く理解するのに役立ちます。

準備

ステップ1: トークンの初期化

  • 好きなテキストエディタを開きます。できれば、前回のチュートリアルで使用したフォルダー内から開いてください。
  • token.luaという新しいファイルを作成します。
  • token.lua内で、トークンの状態を初期化し、残高、名前、ティッカーなどを定義します。
lua
local json = require('json')

if not Balances then Balances = { [ao.id] = 100000000000000 } end

if Name ~= 'My Coin' then Name = 'My Coin' end

if Ticker ~= 'COIN' then Ticker = 'COIN' end

if Denomination ~= 10 then Denomination = 10 end

if not Logo then Logo = 'optional arweave TXID of logo image' end

token.lua image 1

ここで行ったことを分解してみましょう:

  • local json = require('json'): このコードの最初の行は、後で使用するためのモジュールをインポートします。

  • if not Balances then Balances = { [ao.id] = 100000000000000 } end: この2行目は、トークンを所有する人を追跡するためのBalancesテーブルを初期化しています。トークンプロセスao.idを初期状態で全残高を持つように初期化します。

  • 次の4行、if Nameif Tickerif Denominationif not Logoはすべてオプションですが、if Denominationを除いて、トークンの名前、ティッカー、単位、ロゴをそれぞれ定義するために使用されます。

INFO

コードif Denomination ~= 10 then Denomination = 10 endは、単位として扱うべきトークンの数を示しています。

ステップ2: InfoおよびBalancesハンドラ


受信メッセージハンドラ

次に、受信メッセージを処理するための最初のハンドラを追加しましょう。

lua
Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
  ao.send(
      { Target = msg.From, Tags = { Name = Name, Ticker = Ticker, Logo = Logo, Denomination = tostring(Denomination) } })
end)

Token.lua image 2

INFO

この時点で、私たちがすべてのハンドラをtoken.luaファイル内に構築していることに気付いたかもしれません。.editorを使用していない理由です。

多くのハンドラやプロセスがある場合、.editorを使用してハンドラを作成することは完全に問題ありませんが、トークンの初期化、情報および残高ハンドラ、転送ハンドラ、ミントハンドラを設定する完全なプロセスを作成しているため、すべてを1つのファイルにまとめるのが最善です。

これにより、一貫性を保つこともできます。なぜなら、token.luaファイルをaosに再読み込みするたびに、各ハンドラが更新されるからです。

このコードは、誰かがタグAction = "info"のメッセージを送信した場合、私たちのトークンが上記で定義されたすべての情報を含むメッセージを返すことを意味します。Target = msg.Fromに注意してください。これは、aoがこのメッセージを送信したプロセスに返信していることを示します。

情報およびトークン残高ハンドラ

次に、トークンの残高に関する情報を提供する2つのハンドラを追加できます。

lua
Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
  local bal = '0'

  -- If not Target is provided, then return the Senders balance
  if (msg.Tags.Target and Balances[msg.Tags.Target]) then
    bal = tostring(Balances[msg.Tags.Target])
  elseif Balances[msg.From] then
    bal = tostring(Balances[msg.From])
  end

  ao.send({
    Target = msg.From,
    Tags = { Target = msg.From, Balance = bal, Ticker = Ticker, Data = json.encode(tonumber(bal)) }
  })
end)

Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
             function(msg) ao.send({ Target = msg.From, Data = json.encode(Balances) }) end)

最初のハンドラHandlers.add('balance'は、自分の残高またはターゲットの残高を要求しているプロセスや人に対応します。その後、情報を含むメッセージで返信します。2つ目のハンドラHandlers.add('balances'は、残高テーブル全体で返信します。

ステップ3: 転送ハンドラ

テストを開始する前に、プロセスやユーザー間でトークンを転送するための2つのハンドラを追加します。

lua
Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
  assert(type(msg.Tags.Recipient) == 'string', 'Recipient is required!')
  assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

  if not Balances[msg.From] then Balances[msg.From] = 0 end

  if not Balances[msg.Tags.Recipient] then Balances[msg.Tags.Recipient] = 0 end

  local qty = tonumber(msg.Tags.Quantity)
  assert(type(qty) == 'number', 'qty must be number')

  if Balances[msg.From] >= qty then
    Balances[msg.From] = Balances[msg.From] - qty
    Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty

    --[[
      Only Send the notifications to the Sender and Recipient
      if the Cast tag is not set on the Transfer message
    ]] --
    if not msg.Tags.Cast then
      -- Debit-Notice message template, that is sent to the Sender of the transfer
      local debitNotice = {
        Target = msg.From,
        Action = 'Debit-Notice',
        Recipient = msg.Recipient,
        Quantity = tostring(qty),
        Data = Colors.gray ..
            "You transferred " ..
            Colors.blue .. msg.Quantity .. Colors.gray .. " to " .. Colors.green .. msg.Recipient .. Colors.reset
      }
      -- Credit-Notice message template, that is sent to the Recipient of the transfer
      local creditNotice = {
        Target = msg.Recipient,
        Action = 'Credit-Notice',
        Sender = msg.From,
        Quantity = tostring(qty),
        Data = Colors.gray ..
            "You received " ..
            Colors.blue .. msg.Quantity .. Colors.gray .. " from " .. Colors.green .. msg.From .. Colors.reset
      }

      -- Add forwarded tags to the credit and debit notice messages
      for tagName, tagValue in pairs(msg) do
        -- Tags beginning with "X-" are forwarded
        if string.sub(tagName, 1, 2) == "X-" then
          debitNotice[tagName] = tagValue
          creditNotice[tagName] = tagValue
        end
      end

      -- Send Debit-Notice and Credit-Notice
      ao.send(debitNotice)
      ao.send(creditNotice)
    end
  else
    ao.send({
      Target = msg.Tags.From,
      Tags = { Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }
    })
  end
end)

このコードは、受取人と数量のタグが提供されていることを確認し、メッセージを送信している人と受取人の残高を初期化します(存在しない場合)そして、指定された数量を残高テーブル内の受取人に転送しようとします。

lua
Balances[msg.From] = Balances[msg.From] - qty
Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty

転送が成功した場合、元のメッセージの送信者にデビット通知が送信され、受取人にはクレジット通知が送信されます。

lua
-- Send Debit-Notice to the Sender
ao.send({
    Target = msg.From,
    Tags = { Action = 'Debit-Notice', Recipient = msg.Tags.Recipient, Quantity = tostring(qty) }
})
-- Send Credit-Notice to the Recipient
ao.send({
    Target = msg.Tags.Recipient,
    Tags = { Action = 'Credit-Notice', Sender = msg.From, Quantity = tostring(qty) }
})

転送のための残高が不足している場合、失敗メッセージを返します。

lua
ao.send({
    Target = msg.Tags.From,
    Tags = { Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }
})

if not msg.Tags.Cast thenという行は、キャストタグが設定されている場合、メッセージをプッシュしないことを意味します。これはaoプロトコルの一部です。

ステップ4: ミントハンドラ

最後に、新しいトークンをミントするためのハンドラを追加します。

lua
Handlers.add('mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg, env)
  assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

  if msg.From == env.Process.Id then
    -- Add tokens to the token pool, according to Quantity
    local qty = tonumber(msg.Tags.Quantity)
    Balances[env.Process.Id] = Balances[env.Process.Id] + qty
  else
    ao.send({
      Target = msg.Tags.From,
      Tags = {
        Action = 'Mint-Error',
        ['Message-Id'] = msg.Id,
        Error = 'Only the Process Owner can mint new ' .. Ticker .. ' tokens!'
      }
    })
  end
end)

このコードは、数量タグが提供されていることを確認し、指定された数量を残高テーブルに追加します。

ロードとテスト

token.luaファイルを作成したら、または.load-blueprint tokenを使用したら、テストを開始する準備が整いました。

1 - aosプロセスを開始

ターミナルでaosを実行して、aosプロセスを開始したことを確認してください。

2 - token.luaファイルをロード

ガイドに従った場合、aosプロセスと同じディレクトリにtoken.luaファイルがあるはずです。aosプロンプトからファイルをロードします。

lua
.load token.lua

3 - トークンのテスト

今、aosプロセスIDにメッセージを送信して動作しているかどうか確認できます。ターゲットにao.idを使用すると、自分自身にメッセージを送信していることになります。

lua
Send({ Target = ao.id, Action = "Info" })

これにより、契約で定義された情報が表示されるはずです。最新の受信ボックスメッセージで応答を確認してください。

lua
Inbox[#Inbox].Tags

契約で定義された情報が表示されるはずです。

INFO

最後のメッセージを数値で確認することを忘れないでください。そのために、まず#Inboxを実行して受信ボックス内のメッセージの合計数を確認します。その後、最後のメッセージ番号を実行してデータを確認します。

Example:

If #Inbox returns 5, then run Inbox[5].Data to see the data. :::

4 - 転送

次に、他のウォレットまたはプロセスIDにトークンの残高を転送してみてください。

INFO

別のプロセスIDが必要な場合は、別のターミナルウィンドウでaos [name]を実行して新しいプロセスIDを取得できます。同じaos [name]ではないことを確認してください。

Example:

If you're using aos in one terminal window, you can run aos test in another terminal window to get a new process id. :::

lua
Send({ Target = ao.id, Tags = { Action = "Transfer", Recipient = 'another wallet or processid', Quantity = '10000' }})

送信後、ターミナルにDebit-Noticeが送信者側に、Credit-Noticeが受取人側に表示されるメッセージが印刷されます。

5 - 残高を確認

トークンを転送したので、残高を確認してみましょう。

lua
Send({ Target = ao.id, Tags = { Action = "Balances" }})
lua
Inbox[#Inbox].Data

2つのプロセスIDまたはウォレットアドレスが表示され、それぞれが残高を表示します。最初は送信プロセスID、2番目は受取人のプロセスIDである必要があります。

6 - トークンのミント

最後に、いくつかのトークンをミントしようとしてください。

lua
Send({ Target = ao.id, Tags = { Action = "Mint", Quantity = '1000' }})

And check the balances again.

lua
Send({ Target = ao.id, Tags = { Action = "Balances" }})
Inbox[#Inbox].Data

その後、トークンをミントしたプロセスIDの残高が増加したことが確認できます。

結論

これで「トークンを作成する」ガイドは終了です。カスタムトークンを作成する方法を学ぶことで、プロジェクトに大きな可能性が開かれます。それは新しい通貨を作成すること、ゲーム用のトークンを作成すること、ガバナンストークンを作成すること、または想像できるすべてのことです。